<?php

namespace app\common\services\table;

use think\facade\Db;
use think\Model;

class DataTable extends BaseTable
{
    // 自定义设置的参数
    protected array $customFieldConfigs = [];
    // 操作
    protected array $operation = [];
    // 过滤的字段
    public $filterFields = [];
    // 隐藏的字段
    public $hideFields = [];

    // 多项选择操作
    protected bool $selection = true;
    // 启用排序
    protected bool $sort = true;

    // 在字段前插入
    protected $beforeFields = [];

    // 在字段后插入
    protected $afterFields = [];

    // 导出时排除的字段
    public $filterExportFields = [];

    // 启用slot的字段
    protected $fieldUseSlot = [];

    // 远程搜索地址
    public $remoteUrls = [];


    public function __construct(Model $model)
    {
        parent::__construct($model);
        $this->filterFields = ['plaid', 'delete_time', 'config', 'appid'];
        $this->filterExportFields = ['operation'];
    }

    public function Column()
    {
        return new Column();
    }

    // 隐藏表格多项选择框
    public function hideSelection()
    {
        $this->selection = false;
        return $this;
    }

    /**
     * 操作
     * @return DataTable
     */
    public function operation($operation = [])
    {
        if ($operation) {
            $this->operation = $operation;
        } else {
            $buttons = [
                [

                    'render'      => 'tipButton',
                    'name'        => 'edit',
                    'title'       => '编辑',
                    'text'        => '',
                    'type'        => 'primary',
                    'icon'        => 'Edit',
                    'class'       => 'table-row-edit',
                    'disabledTip' => false,
                ],
                [
                    'render'      => 'confirmButton',
                    'name'        => 'delete',
                    'title'       => '删除',
                    'text'        => '',
                    'type'        => 'danger',
                    'icon'        => 'Delete',
                    'class'       => 'table-row-delete',
                    'disabledTip' => false,
                    'popconfirm'  => [
                        'confirmButtonText' => '确认删除',
                        'cancelButtonText'  => '关闭',
                        'confirmButtonType' => 'danger',
                        'title'             => '您确定要删除所选记录吗？',
                    ]
                ]
            ];
            if ($this->sort) {
                array_unshift($buttons, [
                    'render'      => 'moveButton',
                    'name'        => 'weigh-sort',
                    'title'       => '拖拽排序',
                    'text'        => '',
                    'type'        => 'info',
                    'icon'        => 'Rank',
                    'class'       => 'table-row-weigh-sort',
                    'disabledTip' => false,
                ]);
            }
            $this->operation = $this->Column()
                ->prop('operation')
                ->label('操作')
                ->render('buttons')
                // 设置宽度
                ->width(120)
                ->other('fixed', 'right')
                // 禁止搜索
                ->operator(false)
                ->buttons($buttons)
                ->create();
        }
        return $this;
    }

    /**
     * 是否使用注释
     * @param bool $useComment
     * @return $this
     */
    public function useComment(bool $useComment): self
    {
        $this->useComment = $useComment;
        return $this;
    }

    /**
     * 设置字段
     * @param $configs
     * @return $this
     */
    public function setFields($configs)
    {
        $this->customFieldConfigs = array_merge($this->customFieldConfigs, $this->getKeyArray($configs, 'prop'));
        return $this;
    }

    /**
     * 设置单个字段
     * @param string $fieldName
     * @param array $config
     * @return $this
     */
    public function setField(string $fieldName, array $config): self
    {
        if (empty($config['prop'])) {
            $config['prop'] = $fieldName;
        }
        $this->customFieldConfigs[$fieldName] = $config;
        return $this;
    }

    /**
     * 获取数据库信息
     * @return array
     */
    protected function getColumnByFields(): array
    {
        $columns = [];
        $prefix = config('database.connections.mysql.prefix');

        $table_name = $prefix . strtolower($this->tableName);

        $query = "SHOW FULL COLUMNS FROM `{$table_name}`";

        $data = Db::query($query);
        foreach ($data as $key => $value) {
            $column = [
                'prop'  => $value['Field'],
                'label' => $value['Comment'] ?: ($this->fieldComment[$value['Field']] ?? $value['Field']),
                'type'  => $this->getTableColumnsDataType($value)
            ];

            if (strpos($column['label'], ':') !== false) {
                list($label, $values) = explode(':', $column['label']);
                $column['label'] = $label;
                $replaceValues = array_map(function ($item) {
                    return explode('=', $item);
                }, explode(',', $values));
                $column['replaceValue'] = array_column($replaceValues, 1, 0);
            }

            $columns[] = $column;
        }
        return $columns;
    }

    public function create(): array
    {
        $columns = [];

        // 如果启用了 useComment，获取表的字段信息
        $TableColumn = $this->useComment ? $this->getColumnByFields() : [];
        $TableColumnKeyVal = $this->getKeyArray($TableColumn, 'prop');
        // 判断是否存在fields
        if ($this->fields) {
            foreach ($this->fields as $key => $value) {
                $column = [
                    'prop'  => $value,
                    'label' => $value
                ];
                if (isset($TableColumnKeyVal[$value])) {
                    $column = array_merge($column, $TableColumnKeyVal[$value]);
                }

                if (!empty($this->customFieldConfigs[$value])) {
                    $column = array_merge($column, $this->customFieldConfigs[$value]);
                }

                $columns[] = $column;
            }
        } else {
            $columns = $this->getColumnByFields();
        }

        if ($this->operation) {
            $columns[] = $this->operation;
        }
        $_columns = [];
        if ($this->selection) {
            $_columns[] = array(
                'type'     => 'selection',
                'align'    => 'center',
                'operator' => false
            );
        }
        $sortables = ['weigh', 'sort', 'id'];
        foreach ($columns as $k => $column) {
            if (!isset($column['prop'])) continue;
            if (in_array($column['prop'], $this->filterFields)) continue;
            if (in_array($column['prop'], $this->hideFields)) $column['show'] = false;
            if (in_array($column['prop'], $sortables)) {
                $column['sortable'] = 'custom';
            }
            // 添加搜索Placeholder
            if ($column['label']) {
                $column['operatorPlaceholder'] = "搜索" . $column['label'];
            }
            $type = $column['type'] ?? '';
            if (in_array($type, ['dkTinyEditor'])) continue;
            switch ($type) {
                case 'pk':
                    $column['width'] = 80;
                    break;
                case 'switches':
                    $column['render'] = 'switch';
                    break;
                case 'dkImageList':
                    $column['render'] = 'images';
                    $column['operator'] = "LIKE";
                    break;
                case 'dkImage':
                    $column['render'] = 'image';
                    $column['operator'] = "LIKE";
                    break;
                case 'DkIconInput':
                    $column['render'] = 'icon';
                    $column['operator'] = "LIKE";
                    break;
                case 'color':
                    $column['render'] = 'color';
                    $column['width'] = '80';
                    break;
                case 'url':
                    $column['render'] = 'url';
                    $column['width'] = '150';
                    $column['operator'] = "LIKE";
                    break;
                case 'dateTime':
                case 'timestamp':
                    $column['render'] = 'datetime';
                    $column['operator'] = 'RANGE';
                    $column['width'] = '150';
                    $column['sortable'] = 'custom';
                    break;
                case 'date':
                    $column['sortable'] = 'custom';
                    break;
                case 'time':
                    $column['render'] = 'time';
                    $column['operator'] = 'RANGE';
                    $column['width'] = '150';
                    $column['sortable'] = 'custom';
                    break;
                case 'year':
                    $column['render'] = 'year';
                    $column['sortable'] = 'custom';
                    break;
                case 'number':
                    $column['sortable'] = 'custom';
                    break;
                case 'radio':
                    $column['comSearchRender'] = 'select';
                    $column['render'] = 'tag';
                    if ($column['replaceValue']) {
                        $custom = [];
                        $default_custom = ['danger', 'primary', 'success', 'info', 'warning'];
                        foreach ($column['replaceValue'] as $key => $value) {
                            if (isset($default_custom[$key])) {
                                $custom[$key] = $default_custom[$key];
                            } else {
                                $custom[$key] = "primary";
                            }
                        }
                        $column['custom'] = $custom;
                    }
                    break;
                case 'remoteSelect':
                    $column['comSearchRender'] = 'remoteSelect';
                    $column['remoteUrl'] = $this->remoteUrls[$column['prop']] ?? '';
                    break;
            }

            // 通过setField赋值出来的给出优先级
            if (!empty($this->customFieldConfigs[$column['prop']])) {
                $column = array_merge($column, $this->customFieldConfigs[$column['prop']]);
            }
            // 如果存在render，则添加_slot
            if (
                (isset($column['slotName']) && $column['slotName'] === true)
                ||
                (!empty($column['render']) && empty($column['slotName']))
                || in_array($column['prop'], $this->fieldUseSlot)
            ) {
                $column['slotName'] = $column['prop'] . '_slot';
            }

            $column['export'] = !in_array($column['prop'], $this->filterExportFields);
            if (isset($this->beforeFields[$column['prop']])) {
                $before = $this->beforeFields[$column['prop']];
                if (isset($before[0])) {
                    // 多维
                    array_push($_columns, ...$before);
                } else {
                    $_columns[] = $before;
                }
            }
            $_columns[] = $column;
            if (isset($this->afterFields[$column['prop']])) {
                $after = $this->afterFields[$column['prop']];
                if (isset($after[0])) {
                    // 多维
                    array_push($_columns, ...$after);
                } else {
                    $_columns[] = $after;
                }
            }
        }

        return $_columns;
    }


    // 设置排序
    public function setSort(bool $sort)
    {
        $this->sort = $sort;
        return $this;
    }

    /**
     * 设置插入字段前
     * @param array $beforeFields
     * @return $this
     */
    public function setBeforeFields(array $beforeFields)
    {
        $this->beforeFields = $beforeFields;
        return $this;
    }

    /**
     * 设置插入字段后
     * @param array $afterFields
     * @return $this
     */
    public function setAfterFields(array $afterFields)
    {
        $this->afterFields = $afterFields;
        return $this;
    }

    /**
     * 设置插入字段前
     * @param array $beforeFields
     * @return $this
     */
    public function setBeforeField($field, $column)
    {
        $this->beforeFields[$field] = $column;
        return $this;
    }

    /**
     * 设置插入字段后
     * @param array $afterFields
     * @return $this
     */
    public function setAfterField($field, $column)
    {
        $this->afterFields[$field] = $column;
        return $this;
    }

    /**
     * 替换过滤的字段
     * @param array|string[] $filterFields
     */
    public function setFilterFields(array $filterFields)
    {
        $this->filterFields = $filterFields;
        return $this;
    }

    /**
     * 添加过滤的字段
     * @param string|array $filterField
     */
    public function setFilterField($filterField)
    {
        if (is_array($filterField)) {
            $this->filterFields = array_merge($this->filterFields, $filterField);
        } else {
            $this->filterFields[] = $filterField;
        }
        return $this;
    }


    /**
     * 设置隐藏的字段
     * Create by :  刘泓宾<514660094@qq.com>
     * @param $hideField
     * @return $this
     */
    public function setHideFields($hideField)
    {
        if (is_array($hideField)) {
            $this->hideFields = array_merge($this->hideFields, $hideField);
        } else {
            $this->hideFields[] = $hideField;
        }
        return $this;
    }

    /**
     * 替换过滤的导出字段
     * @param array|string[] $filterExportFields
     */
    public function setFilterExportFields(array $filterExportFields)
    {
        $this->filterExportFields = $filterExportFields;
        return $this;
    }

    /**
     * 添加过滤的导出字段
     * @param string|array $filterExportField
     */
    public function setFilterExportField($filterExportField)
    {
        if (is_array($filterExportField)) {
            $this->filterExportFields = array_merge($this->filterExportFields, $filterExportField);
        } else {
            $this->filterExportFields[] = $filterExportField;
        }
        return $this;
    }

    public function setFieldUseSlot(array $fieldUseSlot)
    {
        $this->fieldUseSlot = $fieldUseSlot;
        return $this;
    }

    /**
     * 设置远程搜索地址
     * @param array $remoteUrls
     * @return $this
     */
    public function setRemoteUrls(array $remoteUrls)
    {
        $this->remoteUrls = $remoteUrls;
        return $this;
    }

}
